// ml278
// Copyright (C) 2008 Bjørn Øivind Bjørnsen, Aleksander Gjermundsen, Knut Andre Tidemann, Thomas Hansen
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

float4x4 matWorldViewProjection;
float4 fvCameraPos;
float4 fvLightPos;

float3 fvInvWavelengths;
float fInnerRadius;
float fOuterRadius;
float fKr4PI;
float fKm4PI;
float fKrESun;
float fKmESun;
float fScale;
float fScaleOverScaleDepth;





#define fInvScaleDepth (1.0f / 0.25)
#define fScaleDepth 0.25


// Returns the near intersection point of a line and a sphere
float getNearIntersection(float3 v3Pos, float3 v3Ray, float fDistance2, float fRadius2)
{
   float B = 2.0 * dot(v3Pos, v3Ray);
   float C = fDistance2 - fRadius2;
   float fDet = max(0.0, B*B - 4.0 * C);
   return 0.5 * (-B - sqrt(fDet));
}

// The scale equation calculated by Vernier's Graphical Analysis
float scale(float fCos)
{
   float x = 1.0 - fCos;
   return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
}

struct vertout
{
   float4 pos : POSITION;      // Transformed vertex position
   float4 t0 : TEXCOORD0;         // The Rayleigh color
   float4 t1 : TEXCOORD1;         // The Mie color
   float3 t2 : TEXCOORD2;
};


vertout vs_main(float4 gl_Vertex : POSITION)// fScale / fScaleDepth
{
   // Get the ray from the camera to the vertex and its length (which is the far point of the ray passing through the atmosphere)
   float3 v3Pos = (gl_Vertex.xyz);
   float3 v3Ray = v3Pos - fvCameraPos;
   float fFar = length(v3Ray);
   v3Ray /= fFar;


   // Calculate the ray's start and end positions in the atmosphere, then calculate its scattering offset
   float3 v3Start = fvCameraPos;

   float fStartAngle = dot(v3Ray, v3Start) / fOuterRadius;
   float fStartDepth = exp(-fInvScaleDepth);
   float fStartOffset = fStartDepth*scale(fStartAngle);

   // Initialize the scattering loop variables
   float fSampleLength = fFar / 3.0f;
   float fScaledLength = fSampleLength * fScale;
   float3 v3SampleRay = v3Ray * fSampleLength;
   float3 v3SamplePoint = v3Start + v3SampleRay * 0.5;

   // Now loop through the sample rays
   float3 v3FrontColor = float3(0.0, 0.0, 0.0);
   for(int i=0; i<3; i++)
   {
      float fHeight = length(v3SamplePoint);
      float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
      float fLightAngle = dot(fvLightPos.xyz, v3SamplePoint) / fHeight;
      float fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight;
      float fScatter = (fStartOffset + fDepth*(scale(fLightAngle) - scale(fCameraAngle)));
      float3 v3Attenuate = exp(-fScatter * (fvInvWavelengths * fKr4PI + fKm4PI));
      v3FrontColor += v3Attenuate * (fDepth * fScaledLength);
      v3SamplePoint += v3SampleRay;
   }

   // Finally, scale the Mie and Rayleigh colors and set up the varying variables for the pixel shader
   vertout OUT;
   OUT.pos = mul(matWorldViewProjection,float4(v3Pos,1));
   OUT.t0 = float4(v3FrontColor * (fvInvWavelengths * fKrESun),1);
   OUT.t1 = float4(v3FrontColor * fKmESun,1);
   OUT.t2 = fvCameraPos - v3Pos;
   return OUT;
}

//float4 fvLightPos;
#define fG  -0.990f
#define fG2  -0.990f * -0.990f
//static const float fG2 = fG * fG;
float fExposure;

// Calculates the Mie phase function
float getMiePhase(float fCos, float fCos2, float g, float g2)
{
   return 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos2) / pow(1.0 + g2 - 2.0*g*fCos, 1.5);
}

// Calculates the Rayleigh phase function
float getRayleighPhase(float fCos2)
{
   return 0.75 * (2.0 + 0.5 * fCos2);
   //return 0.75 + 0.75*fCos2;
}

float4 ps_main(float4 c0 : TEXCOORD0,
         float4 c1 : TEXCOORD1,
         float3 v3Direction : TEXCOORD2) : COLOR
{
   float fCos = dot(fvLightPos.xyz, v3Direction) / length(v3Direction);
   float fCos2 = fCos*fCos;
   float4 color = getRayleighPhase(fCos2) * c0 + getMiePhase(fCos, fCos2, fG, fG2) * c1;
   color.a = color.b;
   return 1 - exp(-fExposure * color);
}